Skip to content

test(hooks): add coverage for hook plugin system#1034

Merged
mergify[bot] merged 1 commit intopython-wheel-build:mainfrom
mnadzam:test_hooks
Apr 14, 2026
Merged

test(hooks): add coverage for hook plugin system#1034
mergify[bot] merged 1 commit intopython-wheel-build:mainfrom
mnadzam:test_hooks

Conversation

@mnadzam
Copy link
Copy Markdown
Contributor

@mnadzam mnadzam commented Apr 7, 2026

Closes #1033

@mergify mergify bot added the ci label Apr 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds tests in tests/test_hooks.py for the fromager.hooks API. Introduces an autouse fixture that clears hooks._mgrs between tests. Verifies _die_on_plugin_load_failure raises a RuntimeError including the failing entry point name and preserves the original exception as cause. Tests _get_hooks for correct HookManager construction and caching. Exercises run_post_build_hooks, run_post_bootstrap_hooks, and run_prebuilt_wheel_hooks with mocked managers to assert exception propagation and exact kwargs passed to plugins. Tests log_hooks by mocking _get_dist_info and ExtensionManager and asserting expected calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding test coverage for the hook plugin system in hooks.py.
Description check ✅ Passed The description references issue #1033, which is the source of the test coverage requirements for the hooks plugin system.
Linked Issues check ✅ Passed The PR fully addresses all acceptance criteria: tests for _get_hooks() stevedore manager creation and caching [#1033], run_post_build_hooks() with mocked hooks and argument verification [#1033], exception propagation behavior [#1033], and log_hooks() logging output [#1033].
Out of Scope Changes check ✅ Passed All changes are within scope—the PR adds only test coverage for hooks.py functions specified in #1033 with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_hooks.py (1)

78-78: Consider using a lambda for __iter__ to avoid one-shot iterator brittleness.

Mock(return_value=iter([...])) returns the same iterator object on every call. Once exhausted, subsequent iterations yield nothing. If the implementation ever iterates twice, this mock silently returns an empty sequence on the second pass.

Using __iter__ = lambda: iter([...]) creates a fresh iterator per call, matching real manager behavior.

Suggested pattern (applies to lines 78, 101, 135, 167)
-    fake_mgr.__iter__ = Mock(return_value=iter([_make_fake_ext(bad_plugin)]))
+    fake_mgr.__iter__ = lambda: iter([_make_fake_ext(bad_plugin)])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_hooks.py` at line 78, The test uses Mock(return_value=iter([...]))
for fake_mgr.__iter__ which returns a single, one-shot iterator that becomes
empty after the first iteration; update each occurrence (fake_mgr.__iter__
assignments at the spots using _make_fake_ext, good_plugin/bad_plugin fixtures)
to provide a fresh iterator per call by assigning a callable that returns a new
iterator (e.g., set fake_mgr.__iter__ to a lambda that returns iter([...])) so
iterations behave like a real manager across multiple passes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_hooks.py`:
- Line 78: The test uses Mock(return_value=iter([...])) for fake_mgr.__iter__
which returns a single, one-shot iterator that becomes empty after the first
iteration; update each occurrence (fake_mgr.__iter__ assignments at the spots
using _make_fake_ext, good_plugin/bad_plugin fixtures) to provide a fresh
iterator per call by assigning a callable that returns a new iterator (e.g., set
fake_mgr.__iter__ to a lambda that returns iter([...])) so iterations behave
like a real manager across multiple passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c86be25d-d112-4e48-af6c-a3e1875f1488

📥 Commits

Reviewing files that changed from the base of the PR and between d86f938 and c2cdc3b.

📒 Files selected for processing (1)
  • tests/test_hooks.py

@mnadzam mnadzam marked this pull request as ready for review April 7, 2026 16:57
@mnadzam mnadzam requested a review from a team as a code owner April 7, 2026 16:57
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_hooks.py (1)

126-155: Consider adding exception propagation test for run_post_bootstrap_hooks.

The PR objectives mention verifying exception propagation behavior across hook runners. Currently only run_post_build_hooks has an exception propagation test. For complete coverage, consider adding similar tests for run_post_bootstrap_hooks and run_prebuilt_wheel_hooks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_hooks.py` around lines 126 - 155, Add tests that verify exceptions
raised by hook plugins propagate from run_post_bootstrap_hooks and
run_prebuilt_wheel_hooks the same way as run_post_build_hooks: create a fake
plugin that raises a specific exception, register it via the _get_hooks mock
(similar to test_run_post_bootstrap_hooks_calls_plugin using _make_fake_ext),
call run_post_bootstrap_hooks and run_prebuilt_wheel_hooks with appropriate
minimal args (ctx, req, dist_name, dist_version, sdist_filename/wheel_filename
as needed), and assert the exception is raised (use pytest.raises or
equivalent). Ensure the tests reference the run_post_bootstrap_hooks and
run_prebuilt_wheel_hooks functions and mimic the pattern used in the existing
run_post_build_hooks exception test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_hooks.py`:
- Around line 126-155: Add tests that verify exceptions raised by hook plugins
propagate from run_post_bootstrap_hooks and run_prebuilt_wheel_hooks the same
way as run_post_build_hooks: create a fake plugin that raises a specific
exception, register it via the _get_hooks mock (similar to
test_run_post_bootstrap_hooks_calls_plugin using _make_fake_ext), call
run_post_bootstrap_hooks and run_prebuilt_wheel_hooks with appropriate minimal
args (ctx, req, dist_name, dist_version, sdist_filename/wheel_filename as
needed), and assert the exception is raised (use pytest.raises or equivalent).
Ensure the tests reference the run_post_bootstrap_hooks and
run_prebuilt_wheel_hooks functions and mimic the pattern used in the existing
run_post_build_hooks exception test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 59f3bb97-1d43-467c-ae2a-ac3696c5997b

📥 Commits

Reviewing files that changed from the base of the PR and between c2cdc3b and 67dc1c9.

📒 Files selected for processing (1)
  • tests/test_hooks.py

Copy link
Copy Markdown
Contributor

@rd4398 rd4398 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good! I have left couple of comments after which this should be ready to merge

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_hooks.py`:
- Around line 93-124: The test currently checks plugin kwargs but doesn't verify
hook routing; update the test for run_post_build_hooks to assert that the hooks
discovery function (_get_hooks / mock_get) was invoked with the "post_build"
hook name. Specifically, after calling hooks.run_post_build_hooks(...) add an
assertion like mock_get.assert_called_with("post_build") (or the equivalent call
check matching how _get_hooks is mocked) so the test ensures correct routing to
the post_build hook.
- Around line 231-256: Update the test_log_hooks_logs_each_extension test to
assert emitted log lines from hooks.log_hooks(): use pytest's caplog (or
patching the logger used in fromager.hooks) to capture logs around the
hooks.log_hooks() call and assert that the captured records include messages
referencing ext_a.module_name ("my_plugins.hooks") and ext_b.module_name
("other_plugins.hooks") (and optionally the distribution info returned by
_get_dist_info, i.e., "mypkg" and "1.0.0"); keep the existing mocks
(ExtensionManager and _get_dist_info) and existing assertions about their calls,
but add explicit assertions that the logger produced one log entry per extension
with the expected text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 86ac5682-3acc-4c87-992e-0fa8c0958582

📥 Commits

Reviewing files that changed from the base of the PR and between 67dc1c9 and abfbd10.

📒 Files selected for processing (1)
  • tests/test_hooks.py

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
tests/test_hooks.py (1)

236-259: ⚠️ Potential issue | 🟠 Major

test_log_hooks_logs_each_extension still doesn’t assert emitted log lines.

This test currently validates collaborators only; it does not verify the behavior log_hooks() is meant to provide (per-extension logging), so logging regressions can slip through.

Proposed test hardening
 `@patch`("fromager.hooks.overrides._get_dist_info", return_value=("mypkg", "1.0.0"))
 `@patch`("fromager.hooks.extension.ExtensionManager")
 def test_log_hooks_logs_each_extension(
     mock_em_cls: Mock,
     mock_dist_info: Mock,
+    caplog: pytest.LogCaptureFixture,
 ) -> None:
@@
-    hooks.log_hooks()
+    with caplog.at_level("DEBUG", logger=hooks.logger.name):
+        hooks.log_hooks()
@@
     assert mock_dist_info.call_count == 2
     mock_dist_info.assert_any_call("my_plugins.hooks")
     mock_dist_info.assert_any_call("other_plugins.hooks")
+    messages = [r.getMessage() for r in caplog.records if r.name == hooks.logger.name]
+    assert any("post_build" in m and "my_plugins.hooks" in m for m in messages)
+    assert any("post_bootstrap" in m and "other_plugins.hooks" in m for m in messages)

As per coding guidelines: tests/**: Verify test actually tests the intended behavior. Check for missing edge cases. Flag overly brittle mocks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_hooks.py` around lines 236 - 259, The test currently only asserts
collaborators were called; update test_log_hooks_logs_each_extension to assert
the actual log output from hooks.log_hooks() by capturing emitted logs (e.g.,
using caplog or a logging.Mock) and verifying that a log entry exists for each
extension (ext_a and ext_b) including their names/module_name; locate the test
setup using mocks ext_a/ext_b and the call to hooks.log_hooks() and after
invoking it assert that the captured logs contain messages referencing
"post_build" / "my_plugins.hooks" and "post_bootstrap" / "other_plugins.hooks"
so the test verifies per-extension logging behavior rather than just call
interactions with mock_em_cls and mock_dist_info.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tests/test_hooks.py`:
- Around line 236-259: The test currently only asserts collaborators were
called; update test_log_hooks_logs_each_extension to assert the actual log
output from hooks.log_hooks() by capturing emitted logs (e.g., using caplog or a
logging.Mock) and verifying that a log entry exists for each extension (ext_a
and ext_b) including their names/module_name; locate the test setup using mocks
ext_a/ext_b and the call to hooks.log_hooks() and after invoking it assert that
the captured logs contain messages referencing "post_build" / "my_plugins.hooks"
and "post_bootstrap" / "other_plugins.hooks" so the test verifies per-extension
logging behavior rather than just call interactions with mock_em_cls and
mock_dist_info.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b96525ed-041d-4005-b8f0-2ff813eb11bd

📥 Commits

Reviewing files that changed from the base of the PR and between abfbd10 and 0b016cd.

📒 Files selected for processing (1)
  • tests/test_hooks.py

@mnadzam mnadzam requested a review from rd4398 April 9, 2026 12:06
Copy link
Copy Markdown
Contributor

@rd4398 rd4398 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is good to go. I will wait for others to review as well

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_hooks.py (1)

79-95: Assert hook routing in exception-path tests.

These tests prove exception propagation, but they would still pass if a runner called _get_hooks() with the wrong hook name. Add explicit routing assertions.

Suggested hardening
@@ def test_run_post_build_hooks_exception_propagates(mock_get: Mock) -> None:
     with pytest.raises(ValueError, match="hook failed"):
         hooks.run_post_build_hooks(
             ctx=Mock(),
             req=Requirement("pkg"),
             dist_name="pkg",
             dist_version="1.0",
             sdist_filename=pathlib.Path("/tmp/a.tar.gz"),
             wheel_filename=pathlib.Path("/tmp/a.whl"),
         )
+    mock_get.assert_called_once_with("post_build")
@@ def test_run_post_bootstrap_hooks_exception_propagates(mock_get: Mock) -> None:
     with pytest.raises(ValueError, match="hook failed"):
         hooks.run_post_bootstrap_hooks(
             ctx=Mock(),
             req=Requirement("pkg"),
             dist_name="pkg",
             dist_version="1.0",
             sdist_filename=None,
             wheel_filename=None,
         )
+    mock_get.assert_called_once_with("post_bootstrap")
@@ def test_run_prebuilt_wheel_hooks_exception_propagates(mock_get: Mock) -> None:
     with pytest.raises(ValueError, match="hook failed"):
         hooks.run_prebuilt_wheel_hooks(
             ctx=Mock(),
             req=Requirement("pkg"),
             dist_name="pkg",
             dist_version="1.0",
             wheel_filename=pathlib.Path("/tmp/a.whl"),
         )
+    mock_get.assert_called_once_with("prebuilt_wheel")

As per coding guidelines: tests/**: Verify test actually tests the intended behavior. Check for missing edge cases. Flag overly brittle mocks.

Also applies to: 129-145, 177-192

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_hooks.py` around lines 79 - 95, The test
test_run_post_build_hooks_exception_propagates currently only verifies exception
propagation but not that hooks are routed to the correct hook name; update the
test to assert that the patched _get_hooks was called with the specific hook
name used by run_post_build_hooks (e.g.,
mock_get.assert_called_once_with("post_build", any other expected args if
applicable)), and apply the same explicit routing assertion in the other
exception-path tests mentioned (the tests around the other post-build /
pre-publish cases) so each test verifies both exception propagation and that
_get_hooks was invoked for the intended hook identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_hooks.py`:
- Around line 79-95: The test test_run_post_build_hooks_exception_propagates
currently only verifies exception propagation but not that hooks are routed to
the correct hook name; update the test to assert that the patched _get_hooks was
called with the specific hook name used by run_post_build_hooks (e.g.,
mock_get.assert_called_once_with("post_build", any other expected args if
applicable)), and apply the same explicit routing assertion in the other
exception-path tests mentioned (the tests around the other post-build /
pre-publish cases) so each test verifies both exception propagation and that
_get_hooks was invoked for the intended hook identifier.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8c838951-c208-4ea4-9270-02f164cd3384

📥 Commits

Reviewing files that changed from the base of the PR and between 0b016cd and 6c8fec3.

📒 Files selected for processing (1)
  • tests/test_hooks.py

@LalatenduMohanty
Copy link
Copy Markdown
Member

@mergify rebase

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 13, 2026

Deprecation notice: This pull request comes from a fork and was rebased using bot_account impersonation. This capability will be removed on July 1, 2026. After this date, the rebase action will no longer be able to rebase fork pull requests with this configuration. Please switch to the update action/command to ensure compatibility going forward.

@mergify
Copy link
Copy Markdown
Contributor

mergify bot commented Apr 13, 2026

rebase

✅ Branch has been successfully rebased

Closes python-wheel-build#1033

Signed-off-by: Marcel Nadzam <mnadzam@redhat.com>

Co-Authored-By: Cursor
@mergify mergify bot merged commit 641a6c1 into python-wheel-build:main Apr 14, 2026
39 checks passed
@mnadzam mnadzam deleted the test_hooks branch April 14, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test: add coverage for hook plugin system (hooks.py)

3 participants